package com.block.test.service.impl;


import cn.hutool.core.lang.UUID;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.block.applet.service.AppletCountInfoService;
import com.block.channel.service.IChannelCountPvInfoService;
import com.block.channel.service.IChannelCountUvInfoService;
import com.block.common.constant.RedisKeyConstant;
import com.block.common.model.dto.CountInfoDTO;
import com.block.common.service.LogFactory;
import com.block.common.service.impl.ChannelCommonService;
import com.block.common.util.IpUtil;
import com.block.common.util.LocalDateUtil;
import com.block.db.entity.AppletCountInfo;
import com.block.db.entity.ChannelBaseInfo;
import com.block.test.service.IWxEventCountService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

@Service
public class WxEventCountServiceImpl implements IWxEventCountService {
    private static final Logger log = LogFactory.getCommLog();

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    ChannelCommonService channelCommonService;
    @Autowired
    IChannelCountPvInfoService channelCountPvService;
    @Autowired
    IChannelCountUvInfoService  channelCountUvService;
    @Autowired
    AppletCountInfoService appletCountInfoService;

    @Override
    public void wxEventCount(ChannelBaseInfo channelBaseInfo, String userUuid, String type, HttpServletRequest request, String uid) {
        // 初始化基础信息
        String channelCode = channelBaseInfo.getChannelCode();
        String randomId = UUID.randomUUID().toString(true);
        String reqIp = IpUtil.getIp(request);
        String userAgent = request.getHeader("User-Agent");
        Long remainSecond = LocalDateUtil.getRemainSecondNumber();

        CountInfoDTO pvDto = new CountInfoDTO();
        pvDto.setChannelCode(channelCode);
        pvDto.setPvCount(1);
        channelCommonService.updateChannelCount(pvDto);
        channelCountPvService.savePvCountInfo(channelBaseInfo, randomId, reqIp, userAgent);

        String uvKey = StrUtil.format(RedisKeyConstant.COUNT_UV_KEY, channelCode, reqIp);
        Boolean isNewUv = stringRedisTemplate.opsForValue()
                .setIfAbsent(uvKey, System.currentTimeMillis()+"", remainSecond, TimeUnit.SECONDS);

        if (Boolean.TRUE.equals(isNewUv)) {
            CountInfoDTO uvDto = new CountInfoDTO();
            uvDto.setChannelCode(channelCode);
            uvDto.setUvCount(1);
            channelCommonService.updateChannelCount(uvDto);
            channelCountUvService.saveUvCountInfo(channelBaseInfo, randomId, reqIp, userAgent);
        }
        if (StrUtil.isNotBlank(type)) {
            CountInfoDTO typeDto = new CountInfoDTO();
            typeDto.setChannelCode(channelCode);
            String redisKey = null;
            boolean shouldCount = false;
            boolean needInsert = false;
            String insertType = null;
            switch (type) {
                case "1":
                    typeDto.setAppletCount(1);
                    redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_APPLET_KEY, channelCode, userUuid);
                    shouldCount = true;
                    break;
                case "2":
                    typeDto.setGzhCount(1);
                    redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_GZH_KEY, channelCode, uid);
                    shouldCount = true;
                    needInsert = true;
                    insertType = "2";
                    break;
                case "3":
                    typeDto.setErCount(1);
                    redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_ER_KEY, channelCode, uid);
                    shouldCount = true;
                    needInsert = true;
                    insertType = "3";
                    break;
                case "4":
                    typeDto.setComCount(1);
                    redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_COM_KEY, channelCode, uid);
                    shouldCount = true;
                    break;
                case "5":
                    typeDto.setWxComCount(1);
                    redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_WX_KEY, channelCode, uid);
                    shouldCount = true;
                    needInsert = true;
                    insertType = "5";
                    break;
            }

            if (shouldCount && redisKey != null) {
                Boolean result = stringRedisTemplate.opsForValue()
                        .setIfAbsent(redisKey, System.currentTimeMillis()+"", remainSecond, TimeUnit.SECONDS);
                if (Boolean.TRUE.equals(result)) {
                    try {
                        channelCommonService.updateChannelCount(typeDto);
                        if (needInsert && StrUtil.isNotBlank(uid)) {
                            if ("5".equals(insertType)) {
                                appletCountInfoService.insertWxCount(channelCode, uid, insertType);
                            }else {
                                appletCountInfoService.insertCount(channelCode, uid, insertType);
                            }
                        }
                    } catch (Exception e) {
                        log.info("【事件统计失败】channel={}, type={}, uid={}", channelCode, type, uid, e);
                    }
                }
            }
        }
    }

    @Override
    public void appEventCount(ChannelBaseInfo channelBaseInfo, String userUuid, HttpServletRequest request) {
        CountInfoDTO countInfoDTO = new CountInfoDTO();
        countInfoDTO.setChannelCode(channelBaseInfo.getChannelCode());
        String randomId = UUID.randomUUID().toString(true);
        String reqIp = IpUtil.getIp(request);
        String userAgent = request.getHeader("User-Agent");
        Long remainSecond = LocalDateUtil.getRemainSecondNumber();
        String key = StrUtil.format(RedisKeyConstant.COUNT_UV_KEY, channelBaseInfo.getChannelCode(), reqIp);
        boolean ifAbsent = stringRedisTemplate.opsForValue()
                .setIfAbsent(key, System.currentTimeMillis()+"",remainSecond, TimeUnit.SECONDS);
        //统计pv数
        countInfoDTO.setPvCount(1);
        //统计uv数 根据ip
        if(ifAbsent){
            countInfoDTO.setUvCount(1);
            channelCommonService.updateChannelCount(countInfoDTO);
            channelCountUvService.saveUvCountInfo(channelBaseInfo,randomId,reqIp,userAgent);
        }else {
            channelCommonService.updateChannelCount(countInfoDTO);
        }
        channelCountPvService.savePvCountInfo(channelBaseInfo,randomId,reqIp,userAgent);
    }

    @Override
    public void wxEventCountNotToken(ChannelBaseInfo channelBaseInfo, String userUuid, String type, HttpServletRequest request, String uid) {
        String channelCode = channelBaseInfo.getChannelCode();
        String randomId = UUID.randomUUID().toString(true);
        String reqIp = IpUtil.getIp(request);
        String userAgent = request.getHeader("User-Agent");
        Long remainSecond = LocalDateUtil.getRemainSecondNumber();

        CountInfoDTO pvDto = new CountInfoDTO();
        pvDto.setChannelCode(channelCode);
        pvDto.setPvCount(1);
        channelCommonService.updateChannelCount(pvDto);
        channelCountPvService.savePvCountInfo(channelBaseInfo, randomId, reqIp, userAgent);

        String uvKey = StrUtil.format(RedisKeyConstant.COUNT_UV_KEY, channelCode, reqIp);
        Boolean isNewUv = stringRedisTemplate.opsForValue()
                .setIfAbsent(uvKey, System.currentTimeMillis()+"", remainSecond, TimeUnit.SECONDS);

        if (Boolean.TRUE.equals(isNewUv)) {
            CountInfoDTO uvDto = new CountInfoDTO();
            uvDto.setChannelCode(channelCode);
            uvDto.setUvCount(1);
            channelCommonService.updateChannelCount(uvDto);
            channelCountUvService.saveUvCountInfo(channelBaseInfo, randomId, reqIp, userAgent);
        }

        if (StrUtil.isNotBlank(type)) {
            CountInfoDTO typeDto = new CountInfoDTO();
            typeDto.setChannelCode(channelCode);
            String redisKey = null;
            boolean shouldCount = false;
            switch (type) {
                case "1":
                    typeDto.setAppletCount(1);
                    redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_APPLET_KEY, channelCode, userUuid);
                    shouldCount = true;
                    break;
                case "2":
                    typeDto.setGzhCount(1);
                    redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_GZH_KEY, channelCode, userUuid);
                    shouldCount = true;
                    break;
                case "3":
                    typeDto.setErCount(1);
                    redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_ER_KEY, channelCode, userUuid);
                    shouldCount = true;
                    break;
            }
            if (shouldCount && redisKey != null) {
                Boolean result = stringRedisTemplate.opsForValue()
                        .setIfAbsent(redisKey, System.currentTimeMillis() + "", remainSecond, TimeUnit.SECONDS);
                if(result){
                    channelCommonService.updateChannelCount(typeDto);
                }
            }
        }
    }
}
